sampler2D Image : register(s0);
sampler1D Palette : register(s1);
#if PS14
sampler1D Gamma1 : register(s2);
sampler1D Gamma2 : register(s3);
sampler1D Gamma3 : register(s4);
#endif

float4 Desaturation : register(c1);	// { Desat, 1 - Desat }
float4 PaletteMod : register(c2);
float4 Weights : register(c6);		// RGB->Gray weighting { 77/256.0, 143/256.0, 37/256.0, 1 }
float4 Gamma : register(c7);

float4 TextureLookup(float2 tex_coord)
{
#if PALTEX
	float index = tex2D(Image, tex_coord).x;
	index = index * PaletteMod.x + PaletteMod.y;
	return tex1D(Palette, index);
#else
	return tex2D(Image, tex_coord);
#endif
}

float4 Invert(float4 rgb)
{
#if INVERT
	rgb.rgb = Weights.www - rgb.xyz;
#endif
	return rgb;
}

float Grayscale(float4 rgb)
{
	return dot(rgb.rgb, Weights.rgb);
}

float4 SampleTexture(float2 tex_coord)
{
	return Invert(TextureLookup(tex_coord));
}

// Normal color calculation for most drawing modes.

float4 NormalColor(float2 tex_coord : TEXCOORD0, float4 Flash : COLOR0, float4 InvFlash : COLOR1) : COLOR
{
	return Flash + SampleTexture(tex_coord) * InvFlash;
}

// Copy the red channel to the alpha channel. Pays no attention to palettes.

float4 RedToAlpha(float2 tex_coord : TEXCOORD0, float4 Flash : COLOR0, float4 InvFlash : COLOR1) : COLOR
{
	float4 color = Invert(tex2D(Image, tex_coord));
	color.a = color.r;
	return Flash + color * InvFlash;
}

// Just return the value of c0.

float4 VertexColor(float4 color : COLOR0) : COLOR
{
	return color;
}

// Emulate one of the special colormaps. (Invulnerability, gold, etc.)

float4 SpecialColormap(float2 tex_coord : TEXCOORD0, float4 start : COLOR0, float4 end : COLOR1) : COLOR
{
	float4 color = SampleTexture(tex_coord);
	float4 range = end - start;
	// We can't store values greater than 1.0 in a color register, so we multiply
	// the final result by 2 and expect the caller to divide the start and end by 2.
	color.rgb = 2 * (start + Grayscale(color) * range).rgb;
	// Duplicate alpha semantics of NormalColor.
	color.a = start.a + color.a * end.a;
	return color;
}

// In-game colormap effect: fade to a particular color and multiply by another, with 
// optional desaturation of the original color. Desaturation is stored in c1.
// Fade level is packed int fade.a. Fade.rgb has been premultiplied by alpha.
// Overall alpha is in color.a.
float4 InGameColormap(float2 tex_coord : TEXCOORD0, float4 color : COLOR0, float4 fade : COLOR1) : COLOR
{
	float4 rgb = SampleTexture(tex_coord);

	// Desaturate
#if DESAT
	float3 intensity;
	intensity.rgb = Grayscale(rgb) * Desaturation.x;
	rgb.rgb = intensity.rgb + rgb.rgb * Desaturation.y;
#endif

	// Fade
	rgb.rgb = rgb.rgb * fade.aaa + fade.rgb;

	// Shade and Alpha
	rgb = rgb * color;

	return rgb;
}

// Windowed gamma correction.

float4 GammaCorrection(float2 tex_coord : TEXCOORD0) : COLOR
{
	float4 color = tex2D(Image, tex_coord);
#if !PS14
	color.rgb = pow(color.rgb, Gamma.rgb);
#else
	// On PS14 targets, we can only sample once from each sampler
	// per stage. Fortunately, we have 16 samplers to play with,
	// so we can just set three of them to the gamma texture and
	// use one for each component. Unfortunately, all these
	// texture lookups are probably not as efficient as the pow()
	// solution that later targets make possible.
	color.r = tex1D(Gamma1, color.r * Gamma.w).r;
	color.g = tex1D(Gamma2, color.g * Gamma.w).g;
	color.b = tex1D(Gamma3, color.b * Gamma.w).b;
#endif
	return color;
}

// The burn wipe effect.

sampler2D NewScreen : register(s0);
sampler2D Burn : register(s1);

float4 BurnWipe(float2 coord[2] : TEXCOORD0) : COLOR
{
	float4 color = tex2D(NewScreen, coord[0]);
	float4 alpha = tex2D(Burn, coord[1]);
	color.a = alpha.r * 2;
	return color;
}
